package ws

import (
	"encoding/json"
	"fmt"
	"ims/tools"
	"log"
	"net/http"
	"sync"
	"time"

	"github.com/gogf/gf/frame/g"
	"github.com/gogf/gf/os/gtime"
	"github.com/gogf/gf/util/gconv"
	"github.com/gorilla/websocket"
)

type User struct {
	Conn    *websocket.Conn
	Name    string
	Id      string
	Avator  string
	To_id   string
	Role_id string
}
type Message struct {
	conn        *websocket.Conn
	context     interface{}
	content     []byte
	messageType int
}
type TypeMessage struct {
	Type   interface{} `json:"type"`
	Data   interface{} `json:"data"`
	Status interface{} `json:"status"`
}
type ClientMessage struct {
	Name      string `json:"name"`
	Avator    string `json:"avator"`
	Id        string `json:"id"`
	VisitorId string `json:"visitor_id"`
	Group     string `json:"group"`
	Time      string `json:"time"`
	ToId      string `json:"to_id"`
	Content   string `json:"content"`
	City      string `json:"city"`
	ClientIp  string `json:"client_ip"`
	Refer     string `json:"refer"`
	IsKefu    string `json:"is_kefu"`
}

var ClientList = make(map[string]*User)
var KefuList = make(map[string][]*User)
var message = make(chan *Message, 10)
var upgrader = websocket.Upgrader{}
var Mux sync.RWMutex

func init() {
	upgrader = websocket.Upgrader{
		ReadBufferSize:  1024,
		WriteBufferSize: 1024,
		// 解决跨域问题
		CheckOrigin: func(r *http.Request) bool {
			return true
		},
	}
	//go UpdateVisitorStatusCron()
	go WsServerBackend()
	//给客户端发送ping消息
	WsSendPingToClient()
}

func SendServerJiang(content string) string {
	noticeServerJiang := false
	serverJiangAPI := g.Cfg().GetString("ServerJiangAPI")
	if !noticeServerJiang || serverJiangAPI == "" {
		log.Println("do not notice serverjiang:", serverJiangAPI, noticeServerJiang)
		return ""
	}
	sendStr := fmt.Sprintf("%s,访客来了", content)
	desp := "[登录](https://gofly.sopans.com/main)"
	url := serverJiangAPI + "?text=" + sendStr + "&desp=" + desp
	//log.Println(url)
	res := tools.Get(url)
	return res
}

//发送 服务器响应ws请求的ping
func SendWelcomePing(Conn *websocket.Conn) {
	data := make(map[string]interface{})
	msg := TypeMessage{
		Type:   "ping",
		Status: 200,
	}
	data["now"] = gtime.Now().Unix()
	msg.Data = data
	str, _ := json.Marshal(msg)

	Conn.WriteMessage(websocket.TextMessage, str)

}
func SendClientAppid(Conn *websocket.Conn) {
	data := make(map[string]interface{})
	msg := TypeMessage{
		Type:   "success",
		Status: 200,
	}
	data["appid"] = APPID
	msg.Data = data
	str, _ := json.Marshal(msg)

	Conn.WriteMessage(websocket.TextMessage, str)

}

func PushingMessage(Conn *websocket.Conn, messageType string, data interface{}) {

	msg := TypeMessage{
		Type:   messageType,
		Status: 200,
	}
	msg.Data = data
	str, _ := json.Marshal(msg)

	Conn.WriteMessage(websocket.TextMessage, str)
}

//定时给客户端发送消息判断客户端是否在线
func WsSendPingToClient() {

	data := make(map[string]interface{})
	msg := TypeMessage{
		Type: "ping",
	}
	go func() {
		for {

			data["time"] = gtime.Now().Unix()
			msg.Data = data

			//str, _ := json.Marshal(msg)
			for uuid, wsclient := range ChatRoom {
				n := gtime.Now().Unix() - 1200
				if wsclient.Now < n {
					delete(ChatRoom, uuid)
					//delete(PingClient, uuid)
					log.Println("删除客户端2", uuid)
				}
				// 这里 一定要有定时 检查ChatRoom 列表 已经失去联系的客户端
				// 可以用上面判断 客户端超过多少时间 不发来ping 的过期时间，但是需要服务器端
				//收到ping时 更新 ChatRoom里对应客户端的 now时间。
				//下面这种办法 不可靠，因为有可能网络故障，导致服务器端 链接不到客户端，但是也被移除了。
				/*err := wsclient.Conn.WriteMessage(websocket.TextMessage, str)
				if err != nil {
					delete(ChatRoom, uuid)
					log.Println("删除客户端", uuid)
				}*/
			}

			time.Sleep(15 * time.Second)
		}

	}()
}

//处理收到客户端发来的消息进行分类处理
func WsServerBackend() {
	for {
		message := <-message
		var typeMsg TypeMessage
		json.Unmarshal(message.content, &typeMsg)

		if typeMsg.Type == nil {
			continue
		}

		msgType := typeMsg.Type.(string)
		// log.Println("客户端ws:", string(message.content))

		switch msgType {
		case "user":
			ReciveUserMessage(message)
		//心跳
		case "ping":
			PingHander(message)

		case "to_chat":
			KefuToChat(message)

		case "chat":
			err := ReciveChatMessage(message)
			if err != nil {
				log.Println(err.Error())
			}
		}

	}
}

func AddToChatRoom(conn *websocket.Conn, user map[string]interface{}) {
	uid := gconv.String(user["uid"])
	client := &Wsconn{
		Conn:     conn,
		Appid:    APPID,
		Now:      gtime.Timestamp(),
		Avatar:   gconv.String(user["avatar"]),
		ToUserID: gconv.Int(user["toUserId"]),
		UID:      uid,
		Type:     gconv.String(user["type"]),
		Nickname: gconv.String(user["nickname"]),
		UserId:   gconv.Int(user["user_id"]),
	}
	ChatRoom[uid] = client
	// 加入到 ping的数据列表
	// pc := &PingInfo{
	// 	Appid:    APPID,
	// 	Fd:       0,
	// 	IsOpen:   0,
	// 	ToUserID: gconv.Int(user["toUserId"]),
	// 	Tourist:  gconv.Int(user["is_tourist"]),
	// 	Type:     gconv.String(user["type"]),
	// 	UserId:   gconv.Int(user["user_id"]),
	// }

	// PingClient[uid] = pc
}

//获取当前连接人 信息
func CurrentWsconn(message *Message) *Wsconn {
	var clientUser *Wsconn

	for _, client := range ChatRoom {
		if client.Conn == message.conn {
			clientUser = client
		}
	}
	return clientUser
}

// 把访客的客服更换
func UpdateVisitorUser(visitorId string, toId string) {

	if guest, ok := ClientList[visitorId]; ok {
		guest.To_id = toId
	}

}
